﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace Lm.Common.ExtensionMethods
{
    public static class DataRowExt
    {
        /// <summary>
        /// 活得包含row所有字段的列表
        /// </summary>
        /// <param name="row"></param>
        /// <returns></returns>
        public static List<string> GetColumnsList(this DataRow row)
        {
            return row.Table.GetClolumsList();
        }

        /// <summary>
        /// 把row转换成model
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <param name="treat">Model与Row互相转换时，如果结构不相同时的处理方式</param>
        /// <returns></returns>
        public static T ToModel<T>(this DataRow row, SchemaNotSame treat) where T : IModel, new()
        {
            T model = new T(); 
            List<string> propertyNameList = null;
            if (model.SchemaSameWith(row))
            { propertyNameList = model.GetPropertyList(); }
            else
            {
                switch (treat)
                {
                    case SchemaNotSame.ThrowException:
                        {
                            throw new Exception("Model和Row的结构不同");                        
                        }
                    case SchemaNotSame.UseSource:
                        {
                            propertyNameList = row.GetColumnsList();                            
                            break; 
                        }
                    case SchemaNotSame.UseTarget:
                        {
                            propertyNameList = model.GetPropertyList();
                            break; 
                        }
                }
            }
            foreach (var propertyName in propertyNameList)
            {
                var p = model.GetType().GetProperty(propertyName);
                var data = row[propertyName];
                if (data != DBNull.Value)
                {
                    Type tagertType = null;
                    if (p.PropertyType.IsGenericType)
                    {
                        if (p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        {
                            tagertType = p.PropertyType.GetGenericArguments().First();
                        }
                        else
                        { throw new Exception("实体类不支持Nullable<>以外的其他泛型属性"); }
                    }
                    else
                    { tagertType = p.PropertyType; }
                    object value;
                    if (tagertType != data.GetType())
                    { value = Convert.ChangeType(data, tagertType); }
                    else
                    { value = data; }
                    p.SetValue(model, value, null);
                }
            }
            return model;
        }

        /// <summary>
        /// 比较两个row所有字段是否都具有相同的值
        /// </summary>
        /// <param name="row1"></param>
        /// <param name="row2"></param>
        /// <param name="excludeColumnList"></param>
        /// <returns></returns>
        public static bool SameWith(this DataRow row1, DataRow row2, params string[] excludeColumnList)
        {
            if (row1.SchemaSameWith(row2) == false)
            { return false; }
            var row1Columns = (from DataColumn c in row1.Table.Columns
                               select c.ColumnName).ToList();
            foreach (var c in row1Columns)
            {
                if (excludeColumnList.Contains(c))
                { continue; }
                var c1 = row1[c];
                var c2 = row2[c];               
                if (c1.ToString() != c2.ToString())
                { return false; }
            }
            return true;
        }

        /// <summary>
        /// 比较两个row是否具有相同的结构
        /// </summary>
        /// <param name="row1"></param>
        /// <param name="row2"></param>
        /// <returns></returns>
        public static bool SchemaSameWith(this DataRow row1, DataRow row2)
        {
            return row1.Table.SchemaSameWith(row2.Table);
        }

        /// <summary>
        /// 复制一个row,检查结构是否相同
        /// </summary>
        /// <param name="row1"></param>
        /// <param name="row2"></param>
        public static void DataCopyTo(this DataRow row1, DataRow row2)
        {
            row1.DataCopyTo(row2, true);
        }
        /// <summary>
        /// 复制一个row
        /// </summary>
        /// <param name="row1"></param>
        /// <param name="row2"></param>
        /// <param name="checkSchema">是否检查结构</param>
        public static void DataCopyTo(this DataRow row1, DataRow row2, bool checkSchema)
        {
            if (checkSchema)
            {
                if (row1.SchemaSameWith(row2) == false)
                { throw new Exception("row的结构不同"); }
            }
            foreach (DataColumn c in row1.Table.Columns)
            {
                row2[c.ColumnName] = row1[c.ColumnName];
            }
        }

        /// <summary>
        /// row和model是否具有相同的结构
        /// </summary>
        /// <param name="row"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        public static bool SchemaSameWith(this DataRow row, IModel model)
        {
            var columnsList = row.GetColumnsList();
            var propertyList = model.GetPropertyList();
            if (columnsList.SameWith(propertyList) == false)
            { return false; }
            foreach (var c in columnsList)
            {
                if (row.Table.Columns[c].DataType != model.GetType().GetProperty(c).PropertyType)
                { return false; }
            }
            return true;
        }
    }
}
